using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Windows.Forms;

namespace LeisureCenter.Api
{
    public enum MediaPlayState { Stopped, Paused, Playing, FastForward, FastReverse };
    public enum MediaKind { Unknown, CD, DVD, Music, Video, Picture };
    public enum MediaAspectRatio { Stretched, Letterbox, Crop };
    public enum MediaLoadingState { None, NotFound, Error, Loaded };

    public interface IMedia
    {
        MediaKind Kind { get; }

        string FileName { get; }

        MediaLoadingState LoadingState { get; }
        string LoadingErrorMessage { get; }

        void Preload();
    }

    public abstract class BaseMedia : IMedia
    {
        private string fileName = "";
        protected MediaLoadingState loadingState = MediaLoadingState.None;
        protected string loadingErrorMessage = "";

        protected BaseMedia(string fileName)
        {
            this.fileName = fileName;
        }

        #region IMedia implementation

        public abstract MediaKind Kind { get; }

        public virtual string FileName { get { return fileName; } }

        public MediaLoadingState LoadingState
        {
            get { return loadingState; }
            set { loadingState = value; }
        }

        public string LoadingErrorMessage { get { return loadingErrorMessage; } }

        public virtual void Preload()
        {
        }

        #endregion
    }

    public interface IPositionableMedia : IMedia
    {
        // all times in seconds
        int Duration { get; }
        int Position { get; set; }
        MediaPlayState PlayState { get; }

        // playback
        void Play();
        void Pause();
        void PlayPause();
        void Stop();

        event EventHandler<PlayStateChangeEventArgs> PlayStateChange;
        event EventHandler MediaEnded;
    }

    public class PlayStateChangeEventArgs : EventArgs
    {
        private MediaPlayState previousPlayState;
        public MediaPlayState PreviousPlayState { get { return previousPlayState; } }

        private MediaPlayState newPlayState;
        public MediaPlayState NewPlayState { get { return newPlayState; } }

        public PlayStateChangeEventArgs(MediaPlayState previousPlayState, MediaPlayState newPlayState)
        {
            this.previousPlayState = previousPlayState;
            this.newPlayState = newPlayState;
        }
    }

    public abstract class BasePositionableMedia : BaseMedia, IPositionableMedia
    {
        private MediaPlayState playState = MediaPlayState.Stopped;

        protected virtual void OpenFile()
        {
            PlayState = MediaPlayState.Paused;
        }

        protected virtual void DoPlay()
        {
            PlayState = MediaPlayState.Playing;
        }

        protected virtual void DoPause()
        {
            PlayState = MediaPlayState.Paused;
        }

        protected virtual void DoStop()
        {
            PlayState = MediaPlayState.Stopped;
        }

        protected virtual void OnMediaEnded()
        {
            EventHandler temp = MediaEnded;
            if (temp != null)
            {
                temp(this, null);
            }
        }

        protected BasePositionableMedia(string fileName)
            : base(fileName)
        {
        }

        #region IPositionableMedia implementation

        // all times in seconds
        public abstract int Duration { get; }
        public abstract int Position { get; set; }
        public MediaPlayState PlayState
        {
            get {return playState;}
            set
            {
                if (playState != value)
                {
                    MediaPlayState previousPlayState = playState;
                    playState = value;
                    if (PlayStateChange != null)
                    {
                        PlayStateChange(this, new PlayStateChangeEventArgs(previousPlayState, playState));
                    }
                }
            }
        }

        // playback
        public virtual void Play()
        {
            switch (PlayState)
            {
                case MediaPlayState.Stopped:
                    OpenFile();
                    DoPlay();
                    break;
                case MediaPlayState.Paused:
                    DoPlay();
                    break;
                case MediaPlayState.Playing:
                    break;
                case MediaPlayState.FastForward:
                    break;
                case MediaPlayState.FastReverse:
                    break;
                default:
                    break;
            }
        }

        public virtual void Pause()
        {
            switch (PlayState)
            {
                case MediaPlayState.Playing:
                case MediaPlayState.FastForward:
                case MediaPlayState.FastReverse:
                    DoPause();
                    break;
                default:
                    break;
            }
        }

        public virtual void PlayPause()
        {
            switch (PlayState)
            {
                case MediaPlayState.Stopped:
                    OpenFile();
                    DoPlay();
                    break;
                case MediaPlayState.Paused:
                    DoPlay();
                    break;
                case MediaPlayState.Playing:
                case MediaPlayState.FastForward:
                case MediaPlayState.FastReverse:
                    DoPause();
                    break;
                default:
                    break;
            }
        }

        public virtual void Stop()
        {
            if (PlayState != MediaPlayState.Stopped)
                DoStop();
        }


        public event EventHandler<PlayStateChangeEventArgs> PlayStateChange;
        public event EventHandler MediaEnded;

        #endregion
    }

    public interface ISearchableMedia : IPositionableMedia
    {
        double PlayRate { get; }
    
        void FastForward();
        void FastReverse();
    }

    public abstract class BaseSearchableMedia : BasePositionableMedia, ISearchableMedia
    {
        private double playRate = 1;

        protected BaseSearchableMedia(string fileName)
            : base(fileName)
        {
        }

        #region ISearchableMedia implementation

        public double PlayRate { get { return playRate; } }

        public abstract void FastForward();
        public abstract void FastReverse();

        #endregion
    }

    public interface IVisualMedia : IMedia
    {
        bool FullScreen { get; set; }
        MediaAspectRatio AspectRatio { get; set; }

        void SetPreviewArea(Control control, Rectangle rect);
        void HidePreview();
    }

    public interface IPlaylistMedia : IMedia
    {
        void Previous();
        void Next();

        IEnumerable<string> Titles { get; }
        int Count { get; }
        string GetTitle(int index);

        event EventHandler ItemIndexChanged;
        event EventHandler PlaylistChanged;
    }

    public interface IAudioCdMedia : IPlaylistMedia, IPositionableMedia
    {
        int Track { get; set; }
    }

    public interface IVideoDvdMedia : IPlaylistMedia, IPositionableMedia, IVisualMedia
    {
    }

    public interface IControllableMedia : IMedia
    {
        bool HandleKey(Keys key);
    }
}
